import os
import logging
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.ticker import FuncFormatter
import seaborn as sns
from typing import Dict, List, Tuple, Optional, Union, Any

class QVisualizer:
    """
    增强型可视化模块，提供丰富的图表和实时回测结果展示
    """
    
    def __init__(self, output_dir: str = "./output"):
        """
        初始化可视化器
        
        参数:
            output_dir: 输出目录
        """
        self.output_dir = output_dir
        os.makedirs(output_dir, exist_ok=True)
        
        # 设置绘图样式
        plt.style.use('seaborn-v0_8-darkgrid')
        sns.set_palette("Set2")
        
    def plot_equity_curve(self, data: pd.DataFrame, benchmark_data: Optional[pd.DataFrame] = None,
                         title: str = "策略收益曲线", save_path: Optional[str] = None) -> plt.Figure:
        """
        绘制策略收益曲线
        
        参数:
            data: 回测结果数据
            benchmark_data: 基准数据(可选)
            title: 图表标题
            save_path: 保存路径(可选)
            
        返回:
            matplotlib.Figure: 图表对象
        """
        fig, ax = plt.subplots(figsize=(12, 6))
        
        # 绘制策略收益曲线
        if 'cum_returns' in data.columns:
            data['cum_returns'].plot(ax=ax, label="策略收益", linewidth=2)
        elif 'equity_curve' in data.columns:
            data['equity_curve'].plot(ax=ax, label="策略收益", linewidth=2)
        
        # 绘制基准收益曲线
        if benchmark_data is not None:
            if 'cum_returns' in benchmark_data.columns:
                benchmark_data['cum_returns'].plot(ax=ax, label="基准收益", linewidth=2, linestyle='--')
            elif 'close' in benchmark_data.columns:
                # 计算基准收益率
                benchmark_returns = benchmark_data['close'].pct_change()
                benchmark_cum_returns = (1 + benchmark_returns).cumprod()
                benchmark_cum_returns.plot(ax=ax, label="基准收益", linewidth=2, linestyle='--')
        
        # 设置图表属性
        ax.set_title(title, fontsize=15)
        ax.set_ylabel("累计收益倍数", fontsize=12)
        ax.set_xlabel("日期", fontsize=12)
        ax.legend(fontsize=12)
        ax.grid(True)
        
        # 格式化y轴
        ax.yaxis.set_major_formatter(FuncFormatter(lambda y, _: f'{y:.2f}x'))
        
        # 如果包含回撤数据，标注最大回撤区域
        if 'drawdown' in data.columns:
            max_dd_start, max_dd_end = self._get_max_drawdown_period(data)
            if max_dd_start and max_dd_end:
                ax.axvspan(max_dd_start, max_dd_end, color='red', alpha=0.2, label="最大回撤区间")
                
                max_dd = data['drawdown'].max()
                ax.text(max_dd_end, data.loc[max_dd_end, 'cum_returns'], 
                       f'最大回撤: {max_dd:.2%}', color='red', 
                       fontsize=10, ha='right', va='bottom')
        
        plt.tight_layout()
        
        # 保存图表
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            logging.info(f"收益曲线图表已保存: {save_path}")
            
        return fig
        
    def plot_drawdown(self, data: pd.DataFrame, title: str = "策略回撤分析", 
                     save_path: Optional[str] = None) -> plt.Figure:
        """
        绘制回撤分析图表
        
        参数:
            data: 回测结果数据
            title: 图表标题
            save_path: 保存路径(可选)
            
        返回:
            matplotlib.Figure: 图表对象
        """
        # 计算回撤
        if 'drawdown' not in data.columns and 'cum_returns' in data.columns:
            cum_returns = data['cum_returns']
            rolling_max = cum_returns.cummax()
            drawdown = (cum_returns - rolling_max) / rolling_max
            data['drawdown'] = drawdown
        
        fig, ax = plt.subplots(figsize=(12, 6))
        
        # 绘制回撤曲线
        data['drawdown'].plot(ax=ax, color='crimson', linewidth=2)
        
        # 设置图表属性
        ax.set_title(title, fontsize=15)
        ax.set_ylabel("回撤", fontsize=12)
        ax.set_xlabel("日期", fontsize=12)
        ax.grid(True)
        
        # 格式化y轴为百分比
        ax.yaxis.set_major_formatter(FuncFormatter(lambda y, _: f'{y:.1%}'))
        
        # 突出显示最大回撤
        max_dd = data['drawdown'].min()
        max_dd_idx = data['drawdown'].idxmin()
        
        ax.axhline(y=max_dd, color='r', linestyle='--', alpha=0.5, 
                   label=f'最大回撤: {max_dd:.2%}')
        ax.plot(max_dd_idx, max_dd, 'ro')
        ax.text(max_dd_idx, max_dd*1.1, f'{max_dd:.2%}', color='red',
               fontsize=10, ha='center')
        
        ax.legend(fontsize=12)
        plt.tight_layout()
        
        # 保存图表
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            logging.info(f"回撤分析图表已保存: {save_path}")
            
        return fig
        
    def plot_monthly_returns(self, data: pd.DataFrame, title: str = "月度收益热力图", 
                           save_path: Optional[str] = None) -> plt.Figure:
        """
        绘制月度收益热力图
        
        参数:
            data: 回测结果数据
            title: 图表标题
            save_path: 保存路径(可选)
            
        返回:
            matplotlib.Figure: 图表对象
        """
        # 确保索引是日期类型
        if not isinstance(data.index, pd.DatetimeIndex):
            try:
                data.index = pd.to_datetime(data.index)
            except:
                logging.error("无法将索引转换为日期类型，无法绘制月度收益热力图")
                return None
        
        # 计算每日收益率
        if 'returns' not in data.columns and 'close' in data.columns:
            returns = data['close'].pct_change()
        elif 'returns' in data.columns:
            returns = data['returns']
        else:
            logging.error("数据中没有收益率或收盘价列，无法绘制月度收益热力图")
            return None
        
        # 计算月度收益
        monthly_returns = returns.groupby([returns.index.year, returns.index.month]).apply(
            lambda x: (1 + x).prod() - 1)
        
        # 重塑数据为表格形式
        monthly_returns = monthly_returns.unstack()
        
        # 创建热力图
        fig, ax = plt.subplots(figsize=(12, 8))
        
        # 设置月份名称
        months = ['一月', '二月', '三月', '四月', '五月', '六月', 
                 '七月', '八月', '九月', '十月', '十一月', '十二月']
        
        # 创建热力图
        heatmap = sns.heatmap(monthly_returns, annot=True, fmt='.2%', cmap='RdYlGn',
                            linewidths=1, ax=ax, center=0, annot_kws={"size": 10})
        
        # 设置坐标轴标签
        ax.set_title(title, fontsize=15)
        ax.set_ylabel('年份', fontsize=12)
        ax.set_xlabel('月份', fontsize=12)
        ax.set_xticklabels(months, fontsize=10)
        plt.yticks(rotation=0)
        
        # 添加颜色条
        cbar = ax.collections[0].colorbar
        cbar.set_label('月度收益率', fontsize=12)
        
        plt.tight_layout()
        
        # 保存图表
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            logging.info(f"月度收益热力图已保存: {save_path}")
            
        return fig
        
    def plot_trade_analysis(self, trades: List[Dict], title: str = "交易分析", 
                           save_path: Optional[str] = None) -> plt.Figure:
        """
        绘制交易分析图表
        
        参数:
            trades: 交易记录列表
            title: 图表标题
            save_path: 保存路径(可选)
            
        返回:
            matplotlib.Figure: 图表对象
        """
        if not trades:
            logging.warning("没有交易记录，无法绘制交易分析图表")
            return None
            
        # 转换为DataFrame
        df_trades = pd.DataFrame(trades)
        
        # 创建子图
        fig = plt.figure(figsize=(16, 12))
        gs = fig.add_gridspec(3, 2)
        
        # 1. 交易盈亏分布图
        ax1 = fig.add_subplot(gs[0, 0])
        if 'profit' in df_trades.columns:
            profits = df_trades['profit'].dropna()
            profits = profits[~np.isinf(profits)]  # 去除无限值
            
            sns.histplot(profits, bins=20, kde=True, ax=ax1)
            ax1.axvline(x=0, color='r', linestyle='--')
            ax1.set_title("交易盈亏分布", fontsize=13)
            ax1.set_xlabel("收益率", fontsize=10)
            ax1.set_ylabel("频率", fontsize=10)
            ax1.xaxis.set_major_formatter(FuncFormatter(lambda x, _: f'{x:.2%}'))
        
        # 2. 盈亏统计
        ax2 = fig.add_subplot(gs[0, 1])
        if 'profit' in df_trades.columns:
            win_trades = df_trades[df_trades['profit'] > 0]
            loss_trades = df_trades[df_trades['profit'] < 0]
            
            win_rate = len(win_trades) / len(df_trades) if len(df_trades) > 0 else 0
            avg_win = win_trades['profit'].mean() if len(win_trades) > 0 else 0
            avg_loss = loss_trades['profit'].mean() if len(loss_trades) > 0 else 0
            profit_factor = abs(win_trades['profit'].sum() / loss_trades['profit'].sum()) if loss_trades['profit'].sum() < 0 else float('inf')
            
            stats = {
                '指标': ['交易次数', '胜率', '平均盈利', '平均亏损', '盈亏比', '利润因子'],
                '数值': [
                    len(df_trades),
                    f'{win_rate:.2%}',
                    f'{avg_win:.2%}',
                    f'{avg_loss:.2%}',
                    f'{abs(avg_win/avg_loss) if avg_loss != 0 else np.inf:.2f}',
                    f'{profit_factor:.2f}'
                ]
            }
            
            ax2.axis('off')
            table = ax2.table(cellText=list(zip(stats['指标'], stats['数值'])),
                             loc='center', cellLoc='center', colWidths=[0.5, 0.5])
            table.auto_set_font_size(False)
            table.set_fontsize(12)
            table.scale(1.2, 2)
            ax2.set_title("盈亏统计", fontsize=13)
        
        # 3. 交易持续时间分析
        ax3 = fig.add_subplot(gs[1, 0])
        if 'entry_time' in df_trades.columns and 'exit_time' in df_trades.columns:
            # 计算持仓时间
            df_trades['hold_time'] = (pd.to_datetime(df_trades['exit_time']) - 
                                     pd.to_datetime(df_trades['entry_time'])).dt.days
            
            sns.histplot(df_trades['hold_time'].dropna(), bins=15, kde=True, ax=ax3)
            ax3.set_title("交易持续时间分布", fontsize=13)
            ax3.set_xlabel("持仓天数", fontsize=10)
            ax3.set_ylabel("频率", fontsize=10)
        
        # 4. 交易方向分析
        ax4 = fig.add_subplot(gs[1, 1])
        if 'direction' in df_trades.columns:
            direction_counts = df_trades['direction'].value_counts()
            ax4.pie(direction_counts, labels=direction_counts.index, autopct='%1.1f%%',
                  startangle=90, colors=sns.color_palette("Set2"))
            ax4.set_title("交易方向分布", fontsize=13)
            
        # 5. 交易时间序列
        ax5 = fig.add_subplot(gs[2, :])
        if 'timestamp' in df_trades.columns and 'profit' in df_trades.columns:
            df_trades['timestamp'] = pd.to_datetime(df_trades['timestamp'])
            df_trades.sort_values('timestamp', inplace=True)
            
            ax5.scatter(df_trades['timestamp'], df_trades['profit'], 
                      c=df_trades['profit'].apply(lambda x: 'g' if x > 0 else 'r'),
                      alpha=0.7, s=50)
            ax5.axhline(y=0, color='black', linestyle='-', alpha=0.3)
            ax5.set_title("交易盈亏时间序列", fontsize=13)
            ax5.set_xlabel("交易时间", fontsize=10)
            ax5.set_ylabel("收益率", fontsize=10)
            ax5.yaxis.set_major_formatter(FuncFormatter(lambda y, _: f'{y:.2%}'))
            
            # 添加累积收益线
            ax_twin = ax5.twinx()
            cumulative_returns = (1 + df_trades['profit'].fillna(0)).cumprod()
            ax_twin.plot(df_trades['timestamp'], cumulative_returns, 'b-', linewidth=2, alpha=0.5)
            ax_twin.set_ylabel("累积收益倍数", color='b', fontsize=10)
            ax_twin.tick_params(axis='y', colors='b')
            ax_twin.yaxis.set_major_formatter(FuncFormatter(lambda y, _: f'{y:.2f}x'))
        
        plt.suptitle(title, fontsize=16)
        plt.tight_layout()
        plt.subplots_adjust(top=0.92)
        
        # 保存图表
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            logging.info(f"交易分析图表已保存: {save_path}")
            
        return fig
        
    def plot_strategy_dashboard(self, data: pd.DataFrame, trades: List[Dict] = None,
                             benchmark_data: Optional[pd.DataFrame] = None,
                             metrics: Dict[str, Any] = None,
                             title: str = "策略回测仪表盘",
                             save_path: Optional[str] = None) -> plt.Figure:
        """
        生成策略回测综合仪表盘
        
        参数:
            data: 回测结果数据
            trades: 交易记录(可选)
            benchmark_data: 基准数据(可选)
            metrics: 性能指标字典(可选)
            title: 图表标题
            save_path: 保存路径(可选)
            
        返回:
            matplotlib.Figure: 图表对象
        """
        # 创建仪表盘
        fig = plt.figure(figsize=(16, 12), facecolor='white')
        gs = fig.add_gridspec(3, 3)
        
        # 1. 收益曲线
        ax1 = fig.add_subplot(gs[0, :])
        if 'cum_returns' in data.columns:
            data['cum_returns'].plot(ax=ax1, label="策略收益", linewidth=2)
            
            if benchmark_data is not None and 'cum_returns' in benchmark_data.columns:
                benchmark_data['cum_returns'].plot(ax=ax1, label="基准收益", 
                                                 linewidth=1.5, linestyle='--')
            
            ax1.set_title("累积收益", fontsize=13)
            ax1.set_ylabel("收益倍数", fontsize=10)
            ax1.legend(fontsize=10)
            ax1.grid(True)
            ax1.yaxis.set_major_formatter(FuncFormatter(lambda y, _: f'{y:.2f}x'))
        
        # 2. 回撤曲线
        ax2 = fig.add_subplot(gs[1, :2])
        if 'drawdown' in data.columns:
            data['drawdown'].plot(ax=ax2, color='crimson', linewidth=2)
            ax2.set_title("回撤", fontsize=13)
            ax2.set_ylabel("回撤率", fontsize=10)
            ax2.grid(True)
            ax2.yaxis.set_major_formatter(FuncFormatter(lambda y, _: f'{y:.1%}'))
        elif 'cum_returns' in data.columns:
            # 计算回撤
            cum_returns = data['cum_returns']
            rolling_max = cum_returns.cummax()
            drawdown = (cum_returns - rolling_max) / rolling_max
            drawdown.plot(ax=ax2, color='crimson', linewidth=2)
            ax2.set_title("回撤", fontsize=13)
            ax2.set_ylabel("回撤率", fontsize=10)
            ax2.grid(True)
            ax2.yaxis.set_major_formatter(FuncFormatter(lambda y, _: f'{y:.1%}'))
        
        # 3. 关键指标表格
        ax3 = fig.add_subplot(gs[1, 2])
        if metrics:
            # 选择关键指标
            key_metrics = {
                '指标': ['总收益率', '年化收益率', '最大回撤', '夏普比率', '胜率', '盈亏比'],
                '数值': []
            }
            
            for metric in key_metrics['指标']:
                if metric in metrics:
                    value = metrics[metric]
                    if isinstance(value, float):
                        if metric in ['总收益率', '年化收益率', '最大回撤', '胜率']:
                            formatted_value = f'{value:.2%}'
                        else:
                            formatted_value = f'{value:.2f}'
                    else:
                        formatted_value = str(value)
                    key_metrics['数值'].append(formatted_value)
                else:
                    key_metrics['数值'].append('N/A')
            
            ax3.axis('off')
            table = ax3.table(cellText=list(zip(key_metrics['指标'], key_metrics['数值'])),
                             loc='center', cellLoc='center', colWidths=[0.5, 0.5])
            table.auto_set_font_size(False)
            table.set_fontsize(12)
            table.scale(1.2, 2)
            ax3.set_title("关键绩效指标", fontsize=13)
        
        # 4. 月度收益热力图
        ax4 = fig.add_subplot(gs[2, :])
        if isinstance(data.index, pd.DatetimeIndex) and ('returns' in data.columns or 'close' in data.columns):
            # 计算日收益率
            if 'returns' not in data.columns and 'close' in data.columns:
                returns = data['close'].pct_change()
            else:
                returns = data['returns']
            
            # 计算月度收益
            monthly_returns = returns.groupby([returns.index.year, returns.index.month]).apply(
                lambda x: (1 + x).prod() - 1)
            
            # 重塑数据为表格形式
            monthly_returns = monthly_returns.unstack()
            
            # 设置月份名称
            months = ['一月', '二月', '三月', '四月', '五月', '六月', 
                    '七月', '八月', '九月', '十月', '十一月', '十二月']
            
            # 创建热力图
            sns.heatmap(monthly_returns, annot=True, fmt='.2%', cmap='RdYlGn',
                       linewidths=1, ax=ax4, center=0, annot_kws={"size": 9})
            
            # 设置坐标轴标签
            ax4.set_title("月度收益热力图", fontsize=13)
            ax4.set_ylabel('年份', fontsize=10)
            ax4.set_xlabel('月份', fontsize=10)
            ax4.set_xticklabels(months, fontsize=9)
        
        plt.suptitle(title, fontsize=16)
        plt.tight_layout()
        plt.subplots_adjust(top=0.93, hspace=0.3)
        
        # 保存图表
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            logging.info(f"策略仪表盘已保存: {save_path}")
            
        return fig
        
    def generate_html_report(self, data: pd.DataFrame, trades: List[Dict] = None,
                          benchmark_data: Optional[pd.DataFrame] = None,
                          metrics: Dict[str, Any] = None,
                          strategy_name: str = "未命名策略", 
                          output_path: Optional[str] = None) -> str:
        """
        生成HTML格式的回测报告
        
        参数:
            data: 回测结果数据
            trades: 交易记录(可选)
            benchmark_data: 基准数据(可选)
            metrics: 性能指标字典(可选)
            strategy_name: 策略名称
            output_path: 输出路径(可选)
            
        返回:
            str: HTML报告路径
        """
        # 这里使用简化实现，实际中可以使用模板引擎如Jinja2生成更复杂的HTML报告
        import base64
        from io import BytesIO
        
        # 创建输出目录
        if output_path is None:
            output_path = os.path.join(self.output_dir, f"{strategy_name}_report.html")
        else:
            os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
        
        # 生成各种图表
        figures = []
        try:
            # 1. 生成仪表盘
            dashboard = self.plot_strategy_dashboard(
                data, trades, benchmark_data, metrics, 
                title=f"{strategy_name} - 策略回测仪表盘")
            figures.append(('dashboard', dashboard, "策略仪表盘"))
            
            # 2. 收益曲线
            equity = self.plot_equity_curve(
                data, benchmark_data, title=f"{strategy_name} - 收益曲线")
            figures.append(('equity', equity, "收益曲线"))
            
            # 3. 回撤分析
            drawdown = self.plot_drawdown(
                data, title=f"{strategy_name} - 回撤分析")
            figures.append(('drawdown', drawdown, "回撤分析"))
            
            # 4. 月度收益热力图
            monthly = self.plot_monthly_returns(
                data, title=f"{strategy_name} - 月度收益热力图")
            figures.append(('monthly', monthly, "月度收益热力图"))
            
            # 5. 交易分析
            if trades:
                trades_fig = self.plot_trade_analysis(
                    trades, title=f"{strategy_name} - 交易分析")
                figures.append(('trades', trades_fig, "交易分析"))
                
        except Exception as e:
            logging.error(f"生成图表时出错: {str(e)}")
            
        # 开始构建HTML内容
        html_content = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="utf-8">
            <title>{strategy_name} - 回测报告</title>
            <style>
                body {{
                    font-family: Arial, sans-serif;
                    margin: 0;
                    padding: 20px;
                    background-color: #f5f5f5;
                }}
                .container {{
                    max-width: 1200px;
                    margin: 0 auto;
                    background-color: white;
                    padding: 20px;
                    box-shadow: 0 0 10px rgba(0,0,0,0.1);
                }}
                h1, h2, h3 {{
                    color: #333;
                }}
                .metrics-table {{
                    width: 100%;
                    border-collapse: collapse;
                    margin: 20px 0;
                }}
                .metrics-table th, .metrics-table td {{
                    padding: 12px;
                    text-align: left;
                    border-bottom: 1px solid #ddd;
                }}
                .metrics-table th {{
                    background-color: #f2f2f2;
                }}
                .figure-container {{
                    margin: 30px 0;
                }}
                .figure {{
                    width: 100%;
                    max-width: 1100px;
                    margin: 0 auto;
                    text-align: center;
                }}
                .figure img {{
                    max-width: 100%;
                    box-shadow: 0 0 5px rgba(0,0,0,0.2);
                }}
                .figure-caption {{
                    margin-top: 10px;
                    font-style: italic;
                    color: #666;
                }}
                .footer {{
                    margin-top: 50px;
                    text-align: center;
                    font-size: 12px;
                    color: #999;
                }}
            </style>
        </head>
        <body>
            <div class="container">
                <h1>{strategy_name} - 回测报告</h1>
                <p>生成时间: {pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
        """
        
        # 添加指标表格
        if metrics:
            html_content += """
                <h2>绩效指标</h2>
                <table class="metrics-table">
                    <tr>
                        <th>指标</th>
                        <th>数值</th>
                    </tr>
            """
            
            # 按类别分组指标
            performance_metrics = []
            risk_metrics = []
            trade_metrics = []
            
            for key, value in metrics.items():
                if key in ['总收益率', '年化收益率', '夏普比率', '索提诺比率', '卡玛比率', 
                          '最佳月度收益', '最差月度收益', '最佳季度收益', '最差季度收益']:
                    performance_metrics.append((key, value))
                elif key in ['波动率', '下行波动率', '最大回撤', '最大连亏']:
                    risk_metrics.append((key, value))
                elif key in ['交易次数', '胜率', '平均盈利', '平均亏损', '盈亏比', 
                            '利润因子', '最大连胜']:
                    trade_metrics.append((key, value))
            
            # 添加收益指标
            html_content += '<tr><td colspan="2"><strong>收益指标</strong></td></tr>'
            for key, value in performance_metrics:
                formatted_value = f'{value:.2%}' if isinstance(value, float) else value
                html_content += f'<tr><td>{key}</td><td>{formatted_value}</td></tr>'
                
            # 添加风险指标
            html_content += '<tr><td colspan="2"><strong>风险指标</strong></td></tr>'
            for key, value in risk_metrics:
                formatted_value = f'{value:.2%}' if isinstance(value, float) and key != '最大连亏' else value
                html_content += f'<tr><td>{key}</td><td>{formatted_value}</td></tr>'
                
            # 添加交易指标
            html_content += '<tr><td colspan="2"><strong>交易指标</strong></td></tr>'
            for key, value in trade_metrics:
                if key in ['胜率', '平均盈利', '平均亏损'] and isinstance(value, float):
                    formatted_value = f'{value:.2%}'
                elif isinstance(value, float):
                    formatted_value = f'{value:.4f}'
                else:
                    formatted_value = value
                html_content += f'<tr><td>{key}</td><td>{formatted_value}</td></tr>'
                
            html_content += """
                </table>
            """
        
        # 添加图表
        for fig_id, fig, caption in figures:
            if fig:
                # 将matplotlib图形转换为base64编码
                img_data = BytesIO()
                fig.savefig(img_data, format='png', dpi=120, bbox_inches='tight')
                img_data.seek(0)
                img_base64 = base64.b64encode(img_data.read()).decode()
                
                html_content += f"""
                <div class="figure-container">
                    <h2>{caption}</h2>
                    <div class="figure">
                        <img src="data:image/png;base64,{img_base64}" alt="{caption}">
                        <div class="figure-caption">{caption}</div>
                    </div>
                </div>
                """
                
                # 关闭图形以释放内存
                plt.close(fig)
        
        # 添加页脚和结束标签
        html_content += """
                <div class="footer">
                    <p>由QTorch量化交易框架生成</p>
                </div>
            </div>
        </body>
        </html>
        """
        
        # 写入HTML文件
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(html_content)
            
        logging.info(f"HTML报告已生成: {output_path}")
        
        return output_path
        
    def _get_max_drawdown_period(self, data: pd.DataFrame) -> Tuple[Optional[pd.Timestamp], Optional[pd.Timestamp]]:
        """获取最大回撤区间"""
        if 'drawdown' not in data.columns and 'cum_returns' in data.columns:
            # 计算回撤
            cum_returns = data['cum_returns']
            rolling_max = cum_returns.cummax()
            drawdown = (cum_returns - rolling_max) / rolling_max
            data['drawdown'] = drawdown
            
        if 'drawdown' in data.columns:
            # 获取最大回撤点
            max_dd_idx = data['drawdown'].idxmin()
            
            # 找到最大回撤开始点
            rolling_max_before_dd = data.loc[:max_dd_idx, 'cum_returns'].cummax()
            max_dd_start = rolling_max_before_dd.idxmax()
            
            return max_dd_start, max_dd_idx
            
        return None, None